﻿#if NETSTANDARD2_0 || NETCOREAPP3_0
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Specialized;
using System.Net;

namespace Longbow.Logging
{
    /// <summary>
    /// ILogger 数据库日志内部实现类
    /// </summary>
    internal class DBLogger : ILogger
    {
        private readonly Action<Exception, NameValueCollection> _action;
        private readonly IServiceCollection _services;

        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// <param name="services">IServiceCollection 实例</param>
        /// <param name="action">操作回调函数</param>
        public DBLogger(IServiceCollection services, Action<Exception, NameValueCollection> action)
        {
            _services = services;
            _action = action;
        }

        /// <summary>
        /// 创建上下文作用域
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <param name="state"></param>
        /// <returns></returns>
        public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;

        /// <summary>
        /// 判断当前 logLevel 是否开启日志
        /// </summary>
        /// <param name="logLevel">LogLevel 实例</param>
        /// <returns>开启日志时返回真</returns>
        public bool IsEnabled(LogLevel logLevel) => logLevel == LogLevel.None ? false : logLevel >= LogLevel.Error;

        /// <summary>
        /// 写日志方法
        /// </summary>
        /// <typeparam name="TState">泛型类型</typeparam>
        /// <param name="logLevel">LogLevel 实例</param>
        /// <param name="eventId">eventId 实例</param>
        /// <param name="state">TState 实例</param>
        /// <param name="exception">Exception 实例</param>
        /// <param name="formatter">格式化方法回调函数</param>
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel)) return;

            var nv = new NameValueCollection();
            var _context = _services?.BuildServiceProvider().GetRequiredService<IHttpContextAccessor>().HttpContext;
            if (_context != null)
            {
                nv["ErrorPage"] = _context.Request.Path;
                nv["UserIp"] = _context.Connection.RemoteIpAddress.ToIPv4String();
                nv["UserId"] = _context.User.Identity.Name;
            }
            if (state is NameValueCollection v) nv.Add(v);
            _action?.Invoke(exception, nv);
        }
    }
}
#endif
